/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.dao.impl;

import cn.easyplatform.studio.dao.DaoException;
import cn.easyplatform.studio.dao.DaoUtils;
import cn.easyplatform.studio.dao.SeqDao;
import cn.easyplatform.studio.dos.SerialDo;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class DefaultSeqDao implements SeqDao {

	private DataSource ds;

	public DefaultSeqDao(DataSource dataSource) {
		this.ds = dataSource;
	}

	@Override
	public void create(SerialDo sn) {
		PreparedStatement pstmt = null;
		Connection conn = null;
		try {
			conn = ds.getConnection();
			pstmt = conn
					.prepareStatement("insert into sys_serial_info(keyname,keyvalue,incvalue) values(?,?,?)");
			pstmt.setString(1, sn.getKeyName());
			pstmt.setLong(2, sn.getMaxKey() + sn.getPoolSize());
			pstmt.setInt(3, sn.getIncVal());
			pstmt.executeUpdate();
			sn.setMaxKey(sn.getMaxKey() + sn.getPoolSize());
			sn.setNextKey(sn.getMaxKey() - sn.getPoolSize() + sn.getIncVal());
		} catch (SQLException ex) {
			throw new DaoException(ex.getMessage());
		} finally {
			DaoUtils.closeQuietly(pstmt);
		}
	}

	@Override
	public void delete(String name) {
		PreparedStatement pstmt = null;
		Connection conn = null;
		try {
			conn = ds.getConnection();
			pstmt = conn
					.prepareStatement("delete from sys_serial_info where keyvalue=?");
			pstmt.setString(1, name);
			pstmt.execute();
		} catch (SQLException ex) {
			throw new DaoException(ex.getMessage());
		} finally {
			DaoUtils.closeQuietly(pstmt);
		}
	}

	@Override
	public Long nextval(SerialDo sn) {
		synchronized (sn) {
			if (sn.getNextKey() > sn.getMaxKey()) {
				PreparedStatement pstmt = null;
				ResultSet rs = null;
				Connection conn = null;
				try {
					conn = ds.getConnection();
					pstmt = conn
							.prepareStatement("select keyvalue,incvalue from sys_serial_info where keyname=?");
					pstmt.setString(1, sn.getKeyName());
					rs = pstmt.executeQuery();
					if (rs.next()) {
						Long value = rs.getLong(1);
						sn.setIncVal(rs.getInt(2));
						DaoUtils.closeQuietly(pstmt, rs);
						pstmt = conn
								.prepareStatement("update sys_serial_info set keyvalue=keyvalue+? where keyname=?");
						pstmt.setLong(1, sn.getPoolSize() + sn.getIncVal());
						pstmt.setString(2, sn.getKeyName());
						pstmt.executeUpdate();
						sn.setMaxKey(value + sn.getPoolSize());
						sn.setNextKey(sn.getMaxKey() - sn.getPoolSize()
								+ sn.getIncVal());
					} else {
						DaoUtils.closeQuietly(pstmt, rs);
						rs = null;
						pstmt = conn
								.prepareStatement("insert into sys_serial_info(keyname,keyvalue,incvalue) values(?,?,?)");
						pstmt.setString(1, sn.getKeyName());
						pstmt.setLong(
								2,
								sn.getMaxKey() + sn.getPoolSize()
										+ sn.getIncVal());
						pstmt.setInt(3, sn.getIncVal());
						pstmt.executeUpdate();
						sn.setMaxKey(sn.getMaxKey() + sn.getPoolSize());
						sn.setNextKey(sn.getMaxKey() - sn.getPoolSize()
								+ sn.getIncVal());
					}
					return sn.getNextKey();
				} catch (SQLException ex) {
					throw new DaoException(ex.getMessage());
				} finally {
					DaoUtils.closeQuietly(pstmt, rs);
				}
			} else {
				sn.setNextKey(sn.getNextKey() + sn.getIncVal());
				return sn.getNextKey();
			}
		}
	}

	@Override
	public void reset(SerialDo sn) {
		if (sn == null)
			return;
		synchronized (sn) {
			PreparedStatement pstmt = null;
			ResultSet rs = null;
			sn.setMaxKey(0);
			Connection conn = null;
			try {
				conn = ds.getConnection();
				pstmt = conn
						.prepareStatement("update sys_serial_info set keyvalue=? where keyname=?");
				pstmt.setLong(1,
						sn.getMaxKey() + sn.getPoolSize() + sn.getIncVal());
				pstmt.setString(2, sn.getKeyName());
				pstmt.executeUpdate();
				sn.setMaxKey(sn.getMaxKey() + sn.getPoolSize());
				sn.setNextKey(sn.getMaxKey() - sn.getPoolSize()
						+ sn.getIncVal());
			} catch (SQLException ex) {
				throw new DaoException(ex.getMessage());
			} finally {
				DaoUtils.closeQuietly(pstmt, rs);
			}
		}
	}
}
